package com.luli.service.impl;

/**
 * 陆离
 * 2022/5/31 14:04:39
 */

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.*;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 对索引/模板的查询/更新操作
 */
@Service
public class ESMappingImpl {

    private static final Logger log = LoggerFactory.getLogger(ESMappingImpl.class);

    @Resource
    protected RestHighLevelClient client;

    /**
     * 根据索引名（可模糊）-查询相关索引名
     * @return String[]
     */
    public String[] getIndices(String index){
        GetIndexRequest request = new GetIndexRequest(index);
        //允许不存在的索引
        IndicesOptions indicesOptions = IndicesOptions.fromOptions(true, true, true, false);
        request.indicesOptions(indicesOptions);
        GetIndexResponse response = null;
        String[] indices = new String[]{};
        try {
            response = client.indices().get(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error(" ESMappingService getIndices Cause:{},Message:{}", e.getCause(),e.getMessage());
        }
        if (response != null) {
            indices = response.getIndices();
        }
        return indices;
    }

    /**
     * 查询所有的索引名
     * @return String[]
     */
    public String[] getAllIndices(){
        GetIndexRequest request = new GetIndexRequest();
        GetIndexResponse response = null;
        String[] indices = new String[]{};
        try {
            response = client.indices().get(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error(" ESMappingService getAllIndices Cause:{},Message:{}", e.getCause(),e.getMessage());
        }
        if (response != null) {
            indices = response.getIndices();
        }
        return indices;
    }

    /**
     * 查询现有的所有模板信息
     * @return List
     */
    public List<IndexTemplateMetaData> getAllTemplates(){
        GetIndexTemplatesRequest templatesRequest = new GetIndexTemplatesRequest();
        GetIndexTemplatesResponse templatesResponse = null;
        List<IndexTemplateMetaData> list = new ArrayList<>();
        try {
            templatesResponse = client.indices().getIndexTemplate(templatesRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error(" ESCheckMappingService getAllTemplates query error ", e);
        }
        if(templatesResponse == null){
            return list;
        }
        return templatesResponse.getIndexTemplates();
    }

    /**
     * 判断模板是否已经存在
     * @param template 模板名-需明确
     * @return boolean
     */
    public Boolean isTemplateExist(String template){
        List<IndexTemplateMetaData> list = getAllTemplates();
        if(list.isEmpty()){
            return false;
        }
        List<String> names = list.stream().map(IndexTemplateMetaData::name).collect(Collectors.toList());
        return names.contains(template);
    }

    /**
     * 获取索引映射
     * @param index 索引名-需要明确指定，不能模糊
     * @return map
     */
    public MappingMetaData getIndexMapping(String index){
        GetMappingsRequest getMappingsRequest = new GetMappingsRequest();
        //允许不存在的索引
        IndicesOptions indicesOptions = IndicesOptions.fromOptions(true, true, true, false);
        getMappingsRequest.indicesOptions(indicesOptions);
        getMappingsRequest.indices(index);
        GetMappingsResponse getMappingsResponse = null;
        try {
            getMappingsResponse = client.indices().getMapping(getMappingsRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error(" ESCheckMappingService getIndexMapping query error ", e);
        }
        if(getMappingsResponse == null){
            return null;
        }
        return getMappingsResponse.mappings().get(index);
    }

        /**
         * 获取模板映射
         * @param template 模板名-需要明确指定，不能模糊
         * @return map
         */
        public IndexTemplateMetaData getTemplateMapping(String template){
            GetIndexTemplatesRequest templatesRequest = new GetIndexTemplatesRequest(template);
            GetIndexTemplatesResponse templatesResponse = null;
            try {
                templatesResponse = client.indices().getIndexTemplate(templatesRequest, RequestOptions.DEFAULT);
            } catch (Exception e) {
                log.error(" ESCheckMappingService getTemplateMapping query error ", e);
            }
            if(templatesResponse == null){
                return null;
            }
            return templatesResponse.getIndexTemplates().get(0);
        }

    /**
     * 查询索引是否存在指定字段
     * @param field 字段名
     * @param index 索引名-需要明确指定，不能模糊
     * @return boolean
     */
    public boolean isIndexFieldExist(String field, String index){
        MappingMetaData data = getIndexMapping(index);
        if(null == data){
            return false;
        }
        Map<String, Object> properties = (Map<String, Object>) data.getSourceAsMap().get("properties");
        return properties.containsKey(field);
    }

    /**
     * 查询模板是否存在指定字段
     * @param field 字段名
     * @param template 模板名-需要明确指定，不能模糊
     * @return boolean
     */
    public boolean isTemplateFieldExist(String field, String template){
        IndexTemplateMetaData templateMetaData = getTemplateMapping(template);
        if(null == templateMetaData){
            return false;
        }
        Map<String, Object> properties = (Map<String, Object>) templateMetaData.mappings().getSourceAsMap().get("properties");
        return properties.containsKey(field);
    }

    /**
     * 更新指定索引的mapping
     * @param index 索引名，也支持同类型的比如enis-evnt-*
     * @param map 属性map
     * @return boolean
     */
    public boolean putMapping(String index, Map<String, Object> map){
        PutMappingRequest putMappingRequest = new PutMappingRequest(index);
        putMappingRequest.source(map);
        AcknowledgedResponse acknowledgedResponse = null;
        try {
            acknowledgedResponse = client.indices().putMapping(putMappingRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error(" ESCheckMappingService putMapping update error ", e);
        }
        if(acknowledgedResponse == null){
            return false;
        }
        return acknowledgedResponse.isAcknowledged();
    }

    /**
     * 更新指定模板
     * @param template 模板名
     * @param map 属性map
     * @return boolean
     */
    public boolean putTemplate(String template, Map<String, Object> map){
        PutIndexTemplateRequest templateRequest = new PutIndexTemplateRequest(template);
        templateRequest.source(map);
        AcknowledgedResponse acknowledgedResponse = null;
        try {
            acknowledgedResponse = client.indices().putTemplate(templateRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error(" ESCheckMappingService putTemplate update error ", e);
        }
        if(acknowledgedResponse == null){
            return false;
        }
        return acknowledgedResponse.isAcknowledged();
    }


    /**
     * 构造简单属性map 形如
     * {
     *   "properties": {
     *     "field":{
     *       "type": "",
     *       "format": ""
     *     }
     *   }
     * }}
     * @param field 字段名
     * @param type 字段类型
     * @param format 格式化--可null
     * @return map
     */
    public Map<String, Object> addFieldToIndex(String field, String type, String format){
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> properties = new HashMap<>();
        properties.put(field, getFieldMap(type, format));
        map.put("properties", properties);
        return map;
    }

    private Map<String, Object> getFieldMap(String type, String format){
        Map<String, Object> fieldMap = new HashMap<>();
        fieldMap.put("type", type);
        if(null != format){
            fieldMap.put("format", format);
        }
        return fieldMap;
    }

    /**
     * 构造简单属性map--无格式化
     * @param field 字段名
     * @param type 字段类型
     * @return map
     */
    public Map<String, Object> addFieldToIndex(String field, String type){
        return addFieldToIndex(field, type, null);
    }


    /**
     * 添加/更新字段至指定模板
     * @param templateName 模板名称
     * @param field 字段名
     * @param type 字段类型
     * @param format 格式化
     * @return 新的模板信息
     */
    public Map<String, Object> addFieldToTemplate(String templateName, String field, String type, String format){
        //获取模板现有属性信息
        IndexTemplateMetaData templateMetaData = this.getTemplateMapping(templateName);
        //获取模板所有字段属性
        Map<String, Object> properties = (Map<String, Object>) templateMetaData.mappings().getSourceAsMap().get("properties");
        //增加字段属性
        properties.put(field, getFieldMap(type, format));
        //组装新的模板信息
        return getTemplateMap(properties, templateMetaData);
    }

    /**
     * 添加/更新字段至指定模板--无格式化
     * @param templateName 模板名称
     * @param field 字段名
     * @param type 字段类型
     * @return 新的模板信息
     */
    public Map<String, Object> addFieldToTemplate(String templateName, String field, String type){
        return addFieldToTemplate(templateName, field, type, null);
    }

    /**
     * 构造多种字段属性map
     * @param list 字段信息
     * @return map
     */
//    public Map<String, Object> addFieldToIndexBatch(List<EsMapping> list){
//        Map<String, Object> map = new HashMap<>();
//        Map<String, Object> properties = new HashMap<>();
//        list.forEach(e -> properties.put(e.getField(), getFieldMap(e.getType(), e.getField())));
//        map.put("properties", properties);
//        return map;
//    }

    /**
     * 批量添加/更新字段至指定模板
     * @param templateName 模板名称
     * @param list 字段信息
     * @return 新的模板信息
     */
//    public Map<String, Object> addFieldToTemplateBatch(String templateName, List<EsMapping> list){
//        //获取模板现有属性信息
//        IndexTemplateMetaData templateMetaData = this.getTemplateMapping(templateName);
//        //获取模板所有字段属性
//        Map<String, Object> properties = (Map<String, Object>) templateMetaData.mappings().getSourceAsMap().get("properties");
//        //增加字段属性
//        list.forEach(e -> properties.put(e.getField(), getFieldMap(e.getType(), e.getField())));
//        //组装新的模板信息
//        return getTemplateMap(properties, templateMetaData);
//    }

    /**
     * 构造模板信息，形如：
     * {
     *     "order" : 0,//模板优先级，数字越大，优先级越高，覆盖相同项
     *     "index_patterns" : [//模板匹配的名称方式
     *       "test-*",
     *       "test2-*"
     *     ],
     *     "settings" : {//索引设置
     *       "index" : {
     *         "max_result_window" : "10000000",
     *         "number_of_shards" : "5",//主分片的个数
     *         "number_of_replicas" : "1"//主分片的拷贝分片个数（副本）
     *       }
     *     },
     *     "mappings" : {//字段映射
     *       "properties" : {
     *         "field" : {
     *           "type" : "keyword"
     *         },
     *         ...
     *         ...
     *         }
     *     },
     *     "aliases" : {... }//索引的别名
     * }
     * @param properties 属性map
     * @param templateMetaData 原有模板信息
     * @return map
     */
    private Map<String, Object> getTemplateMap(Map<String, Object> properties, IndexTemplateMetaData templateMetaData){
        Map<String, Object> templateMap = new HashMap<>();
        Map<String, Object> pro = new HashMap<>();
        pro.put("properties", properties);
        templateMap.put("mappings", pro);
        //指定模板范围为原有,必要操作
        templateMap.put("index_patterns", templateMetaData.patterns());
        //原有设置属性信息
        Map<String, Settings> settingsMap = templateMetaData.settings().getAsGroups();
        Map<String, Object> setMap = new HashMap<>();
        settingsMap.forEach((k,v) -> setMap.put(k, JSON.parseObject(v.toString())));
        templateMap.put("settings", setMap);
        return templateMap;
    }

    /**
     * 删除指定索引
     * @param indices The indices to delete. Use "_all" to delete all indices.
     * @return boolean
     */
    public boolean deleteIndices(String... indices){
        DeleteIndexRequest request = new DeleteIndexRequest(indices);
        AcknowledgedResponse response = null;
        try {
            response = client.indices().delete(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error(" ESMappingService deleteIndices error", e);
        }
        if(response == null){
            return false;
        }
        return response.isAcknowledged();
    }

    /**
     * 删除指定模板
     * @param template 模板名
     * @return boolean
     */
    public boolean deleteTemplate(String template){
        DeleteIndexTemplateRequest request = new DeleteIndexTemplateRequest(template);
        AcknowledgedResponse response = null;
        try {
            response = client.indices().deleteTemplate(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error(" ESMappingService deleteTemplate error", e);
        }
        if(response == null){
            return false;
        }
        return response.isAcknowledged();
    }

    /**
     * 新建模板
     * @param templateName
     * @param template
     * @param order
     * @param patterns
     * @return
     */
    public Boolean createTemplateToStr(String templateName, String template, int order,String patterns){
        PutIndexTemplateRequest request = new PutIndexTemplateRequest(templateName);
        //优先级
        request.order(order);
        //模板匹配的名称方式 test-*
        request.patterns(Collections.singletonList(patterns));
        request.source(template, XContentType.JSON);
        AcknowledgedResponse response = null;
        try {
            response = client.indices()
                    .putTemplate(request, RequestOptions.DEFAULT);
        } catch (IOException ioException) {
            log.error("Create Template Error" , ioException.getMessage());
        }
       return response.isAcknowledged();
    }

        //截取某个字符串之后的字符
//        String s = StringUtils.substringBefore("hello_world_ll", "_");
//        System.out.println(s);
        public static void main(String args[]) {
            //实例化数组列表对象
            List < Integer > arr_l = new ArrayList < Integer > ();

            //通过使用add()方法是添加
            //数组列表中的对象
            arr_l.add(10);
            arr_l.add(20);
            arr_l.add(30);
            arr_l.add(40);
            arr_l.add(50);
            arr_l.add(50);
            arr_l.add(50);

            //显示ArrayList-
            System.out.println("Array List: " + arr_l);

            //通过使用singleton()方法是
            //删除元素50
            //removeAll()ArrayList中方法的帮助
            arr_l.removeAll(Collections.singleton(50));

            //显示单例列表
            System.out.println("Collections.singleton(50): " + arr_l);
    }


}
